package utils.global.security;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import utils.global.constant.RestfulJson;
import utils.global.utils.AESUtils;

import java.io.*;
import java.lang.reflect.Parameter;

@Aspect
public class SecurityAop {

    @Autowired
    AESUtils aesUtils;

    @Pointcut("@annotation(annotation)")
    public void security(Security annotation) {
    }

    @Around(value = "security(annotation)", argNames = "joinPoint,annotation")
    public RestfulJson securityAop(ProceedingJoinPoint joinPoint, Security annotation) throws Throwable {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        Object[] args = joinPoint.getArgs();
        if (annotation.decoded()) {
            Parameter[] parameters = signature.getMethod().getParameters();
            for (int i = 0; i < parameters.length; i++) {
                /* 获取解密参数 */
                if (parameters[i].isAnnotationPresent(Security.class)) {

                    Security paramAnnotation = parameters[i].getAnnotation(Security.class);
                    Class<?> type = paramAnnotation.decodedType();

                    // todo 解密 字段内 有空白字符
                    /* 解密算法 */
                    String decoder =
                            aesUtils.decryptByHexString(((StringSecurity) args[i]).getResource()).trim();
                    decoder = decoder.substring(1, decoder.length() - 2);

                    /* 转换 字节 */
                    String[] split = decoder.split(", ");
                    byte[] result = new byte[split.length];
                    for (int j = 0; j < split.length; j++) {
                        result[j] = Byte.parseByte(split[j]);
                    }

                    /* 转换对象 */
                    ((StringSecurity) args[i]).setDecoder(bytesToObject(result, type));
                }
            }
        }

        RestfulJson proceed = (RestfulJson) joinPoint.proceed(args);
        if (annotation.encoded()) {
            return new RestfulJson<>(
                    proceed.getMsg(),
                    proceed.getCode(),
                    aesUtils.encryptIntoHexString(objectToBytes(proceed.getData())));
        }
        return proceed;
    }

    public byte[] objectToBytes(Object object) {
        byte[] bytes = new byte[0];
        try (ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo)) {
            oo.writeObject(object);
            bytes = bo.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    public <T> T bytesToObject(byte[] bytes, Class<T> clazz) throws IOException {
        try (ByteArrayInputStream bi = new ByteArrayInputStream(bytes); ObjectInputStream oi = new ObjectInputStream(bi)) {
            T o = (T) oi.readObject();
            return o;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

}
